package cn.xzzz2020.XJynWeb.ioc.core;

import cn.xzzz2020.XJynWeb.aop.annotation.Aspect;
import cn.xzzz2020.XJynWeb.ioc.core.annotation.Component;
import cn.xzzz2020.XJynWeb.ioc.core.annotation.Controller;
import cn.xzzz2020.XJynWeb.ioc.core.annotation.Repository;
import cn.xzzz2020.XJynWeb.ioc.core.annotation.Service;
import cn.xzzz2020.XJynWeb.utils.ClassUtil;
import cn.xzzz2020.XJynWeb.utils.ValidationUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * bean的容器
 * @author xzzz2020
 * @version 1.0
 * @date 2020/7/31 15:18
 */
//设置私有构造器
@Slf4j
public class BeanContainer {

    //存放所有被标记目标对象的map
    private final Map<Class<?>,Object> beanMap = new ConcurrentHashMap<>();

    //加载Bean注解的列表
    private static final List<Class<? extends Annotation>> BEAN_ANNOTATION
            = Arrays.asList(Component.class, Controller.class, Service.class, Repository.class, Aspect.class);

    //是否被加载
    private boolean loaded = false;
    /**
     * 获取容器实例
     * @return 容器
     */
    public static BeanContainer getInstance() {
        return BeanContainerHolder.HOLDER.getInstance();
    }

    private enum BeanContainerHolder{
        HOLDER;
        private BeanContainer instance;
        BeanContainerHolder(){
            instance = new BeanContainer();
        }

        public BeanContainer getInstance() {
            return instance;
        }
    }

    private BeanContainer() {
    }

    /**
     * 加载Bean到容器中
     * @param packageName 包名称
     */
    public synchronized void loadBeans(String packageName){
        if (isLoaded()){
            log.warn("BeanContainer has been loaded.");
            return;
        }
        Set<Class<?>> classSet = ClassUtil.extractPackageClass(packageName);
        //判断能否加载对象
        if (ValidationUtil.isEmpty(classSet)){
            log.warn("This package "+packageName+" has nothing.");
            return;
        }
        for (Class<?> clazz :classSet){
            for (Class<? extends Annotation> annotation : BEAN_ANNOTATION) {
                //如果类上面标记了自定义的注解，就放入到容器中
                if (clazz.isAnnotationPresent(annotation)){
                    beanMap.put(clazz,ClassUtil.newInstance(clazz,true));
                }
            }
        }
        loaded = true;
    }

    /**
     * 判断是否过容器
     * @return true代表已经加载过容器了
     */
    public boolean isLoaded() {
        return loaded;
    }

    /**
     * 获取加载到容器中bean实例的个数
     * @return
     */
    public int getBeansSize(){
        return beanMap.size();
    }

    /**
     * 添加对象实例到容器中
     * @param clazz 指定对象
     * @param bean 指定实例
     * @return 添加的对象
     */
    public Object addBean(Class<?> clazz,Object bean){
        return beanMap.put(clazz, bean);
    }

    /**
     * 删除容器中bean的实例
     * @param clazz 指定对象
     * @return 删除的对象
     */
    public Object removeBean(Class<?> clazz){
        return beanMap.remove(clazz);
    }

    /**
     * 获取指定对象的实例
     * @param clazz 指定对象
     * @return 指定实例
     */
    public Object getBean(Class<?> clazz){
        return beanMap.get(clazz);
    }

    /**
     * 获取容器中所有对象的集合
     * @return 对象集合
     */
    public Set<Class<?>> getClasses(){
        return beanMap.keySet();
    }

    /**
     * 获取容器中所有实例化对象集合
     * @return 实例化对象集合
     */
    public Set<Object> getBeans(){
        return new HashSet<>(beanMap.values());
    }

    /**
     * 根据注解获取对象集合
     * @param annotation 注解
     * @return
     */
    public Set<Class<?>> getClassesByAnnotation(Class<? extends Annotation> annotation){
        //1.获取beanMap的所有class对象
        Set<Class<?>> keySet = getClasses();
        if(ValidationUtil.isEmpty(keySet)){
            log.warn("nothing in beanMap");
            return null;
        }
        //2.通过注解筛选被注解标记的class对象，并添加到classSet里
        Set<Class<?>> classSet = new HashSet<>();
        for (Class<?> clazz : keySet) {
            if (clazz.isAnnotationPresent(annotation)){
                classSet.add(clazz);
            }
        }
        return classSet.size()>0?classSet:null;
    }

    /**
     * 通过接口或者父类获取实现类或者子类的Class集合，不包括其本身
     *
     * @param interfaceOrClass 接口Class或者父类Class
     * @return Class集合
     */
    public Set<Class<?>> getClassesBySuper(Class<?> interfaceOrClass){
        //1.获取beanMap的所有class对象
        Set<Class<?>> keySet = getClasses();
        if(ValidationUtil.isEmpty(keySet)){
            log.warn("nothing in beanMap");
            return null;
        }
        //2.通过keySet的元素是否是传入的接口或者子类，如果是，并添加到classSet里
        Set<Class<?>> classSet = new HashSet<>();
        for (Class<?> clazz : keySet) {
            //isAssignableFrom可以判断是否是同一个类或者其超类
            if (interfaceOrClass.isAssignableFrom(clazz) && !clazz.equals(interfaceOrClass)){
                classSet.add(clazz);
            }
        }
        return classSet.size()>0?classSet:null;
    }
}
